package com.example.service.impl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.entity.Post;
import com.example.mapper.PostMapper;
import com.example.service.PostService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.utils.RedisUtil;
import com.example.vo.PostVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 公众号：java思维导图
 * @since 2020-08-04
 */
@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    PostMapper postMapper;

    /**
     * 分页
     * @param page  分页信息
     * @param categoryId 分类
     * @param userId    用户
     * @param level    置顶
     * @param recommend    精选
     * @param order   排序
     * @return
     */
    @Override
    public IPage<PostVo> paging(Page page, Long categoryId, Long userId, Integer level, Boolean recommend, String order) {

        if(level == null) level = -1;

        QueryWrapper<Object> wrapper = new QueryWrapper<>()
                .eq(categoryId != null, "category_id", categoryId)
                .eq(userId != null, "user_id", userId)
                .eq(level == 0, "level", 0)
                .gt(level > 0, "level", 0)
                .orderByDesc(order != null, order);

        return postMapper.selectPosts(page,wrapper);
    }





    //用缓存来完成 右侧栏 本周热议排行榜功能，不依赖数据库(初始化数据除外)
    //有人发表评论后，直接用命令+1，并重新计算并集得到排行榜

    /**
     * 1.查询获取最近7天的所有文章（多加一个条件:评论数量大于0）
     * 2.然后把文章的评论数量作为有序集合的分数，文章id作为ID存储到zset中
     * 3.本周热议上有标题标题和评论数量，所以还需要把文章的基本信息存储到redis中
     * 得到文章id后，再从缓存中得到标题等信息，可以使用hash的结构来存储文章的信息
     * 4.功能时本周热议，如果文章发表超过7天就没用了，所以给文章的有序集合设置一个有效时间。超过7天自动删除缓存
     */
    //初始化首页的周评论排行榜
    @Override
    public void initIndexWeekRank() {
        //1.缓存最近7填的文章评论数量
        List<Post> last7DayPost = this.list(new QueryWrapper<Post>()
                //public static DateTime offsetDay(Date date,int offset) 偏移天
                //date - 日期
                //offset - 偏移天数，正数向未来偏移，负数向历史偏移
                //Returns:偏移后的日期
                .ge("created", DateUtil.offsetDay(new Date(), -7)/*.toJdkDate()*/)//DateTime()类的toJdkDate() 返回JDK原生的Date对象
                .select("id,title,user_id,comment_count,view_count,created"));
        //初始化文章的总评论
        for (Post post :
                last7DayPost) {
            String key = "day_rank:" + DateUtil.format(post.getCreated(), DatePattern.PURE_DATE_PATTERN);//yyyyMMdd
            //2.设置有效期
            //between(Date beginDate, Date endDate, DateUnit unit) 判断两个日期相差的时长，只保留绝对值
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;//单位秒 有效时间
            //3.缓存文章到set中，评论数量作为排行标准
            redisUtil.zSet(key, post.getId(), post.getCommentCount());
            //4.设置有效期
            redisUtil.expire(key, expireTime);
            //5.缓存文章基本信息（hash结构）
            this.hashCachePostIdAndTitle(post);
        }
        //7天阅读相加
        this.zUnionAndStoreLast7DaysForLastWeekRank();
    }


    /**
     * 本周评论并集
     * 把最近7天的文章评论数量统计一下
     * 用于首页的7天评论排行榜
     */
    public void zUnionAndStoreLast7DaysForLastWeekRank() {
        String prefix = "day_rank:";
        List<String> otherKeys = new ArrayList<>();
        String currentKey = prefix + DateUtil.format(new Date(), DatePattern.PURE_DATE_PATTERN);
        for (int i = -6; i < 0; i++) {
            Date date = DateUtil.offsetDay(new Date(), i).toJdkDate();
            otherKeys.add(prefix + DateUtil.format(date, DatePattern.PURE_DATE_PATTERN));
        }
        //otherKey=day2,day3,...,day7
        redisUtil.zUnionAndStore(currentKey, otherKeys, "last_week_rank");
    }

    /**
     * hash结构缓存文章标题和id
     *
     * @param post
     */
    private void hashCachePostIdAndTitle(Post post) {
        boolean isExist = redisUtil.hasKey("rank_post_" + post.getId());
        if (!isExist) {
            long between = DateUtil.between(new Date(), post.getCreated(), DateUnit.DAY);
            long expireTime = (7 - between) * 24 * 60 * 60;
            //缓存文章基本信息(hash结构)
            redisUtil.hashSet("rank_post_" + post.getId(), "post:id", post.getId(), expireTime);
            redisUtil.hashSet("rank_post_" + post.getId(), "post:title", post.getTitle(), expireTime);
            redisUtil.hashSet("rank_post_" + post.getId(), "post:commentCount", post.getCommentCount(), expireTime);
        }
    }
}
